package org.zjvis.datascience.web.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.zjvis.datascience.common.annotation.ProjectRoleAuth;
import org.zjvis.datascience.common.annotation.TaskAuth;
import org.zjvis.datascience.common.dto.TaskDTO;
import org.zjvis.datascience.common.dto.graph.GraphActionDTO;
import org.zjvis.datascience.common.dto.graph.GraphDTO;
import org.zjvis.datascience.common.enums.ActionEnum;
import org.zjvis.datascience.common.graph.annotation.CheckNull;
import org.zjvis.datascience.common.graph.annotation.GraphAuth;
import org.zjvis.datascience.common.graph.enums.GraphFileFormatEnum;
import org.zjvis.datascience.common.graph.util.GraphUtil;
import org.zjvis.datascience.common.model.ApiResult;
import org.zjvis.datascience.common.model.ApiResultCode;
import org.zjvis.datascience.common.graph.model.CategoryCleanAction;
import org.zjvis.datascience.common.vo.graph.*;
import org.zjvis.datascience.service.graph.GraphActionService;
import org.zjvis.datascience.service.graph.GraphAnalysisService;
import org.zjvis.datascience.service.graph.GraphInstanceService;
import org.zjvis.datascience.service.graph.GraphService;
import org.zjvis.datascience.service.dag.DAGScheduler;
import com.alibaba.fastjson.JSONObject;
import cn.weiguangfu.swagger2.plus.annotation.ApiPlus;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * @description 图构建接口 Controller
 * @date 2021-11-12
 */
@ApiPlus(value = true)
@RequestMapping("/graph")
@RestController
@Api(tags = "graph", description = "图构建接口")
@Validated
public class GraphController {
    @Autowired
    private GraphService graphService;

    @Autowired
    private DAGScheduler dagScheduler;

    @Autowired
    private GraphInstanceService graphInstanceService;

    @Autowired
    private GraphActionService graphActionService;

    @Autowired
    private GraphAnalysisService graphAnalysisService;

    @PostMapping(value = "/queryGraphByTaskId")
    @ResponseBody
    @ApiOperation(value = "queryGraphByTaskId", notes = "queryGraphByTaskId")
    @Transactional
    public ApiResult<GraphVO> queryGraphByTaskId(HttpServletRequest request,
                                                 @RequestBody @TaskAuth JSONObject params) {
        GraphDTO graphDTO = graphService.queryByTaskId(params.getLong("taskId"));
        if (graphDTO == null) {
            graphDTO = graphService.getEmptyGraphByTaskId(params.getLong("taskId"));
            graphService.save(graphDTO);
        }
        graphAnalysisService.queryIdMap(graphDTO);
        GraphVO graphVO = graphDTO.view();
        return ApiResult.valueOf(graphVO);
    }

    @PostMapping(value = "/queryById")
    @ResponseBody
    @ApiOperation(value = "queryById", notes = "queryById")
    @Transactional
    public ApiResult<GraphVO> queryById(HttpServletRequest request,
                                                 @RequestBody @GraphAuth JSONObject params) {
        GraphDTO graphDTO = graphService.queryById(params.getLong("graphId"));
        graphAnalysisService.queryIdMap(graphDTO);
        GraphVO graphVO = graphDTO.view();
        return ApiResult.valueOf(graphVO);
    }

    @PostMapping(value = "/closeGraphSession")
    @ResponseBody
    @ApiOperation(value = "closeGraphSession", notes = "closeGraphSession")
    @Transactional
    public ApiResult<Void> closeGraphSession(HttpServletRequest request,
                                        @RequestBody JSONObject params) {
//        if (params == null || !params.containsKey("graphId")) {
//            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
//        }
//        graphService.closeGraphSession(params.getLong("graphId"));
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/loadGraphData")
    @ResponseBody
    @ApiOperation(value = "loadGraphData", notes = "loadGraphData")
    @Transactional
    public ApiResult<List<Long>> loadGraphData(HttpServletRequest request,
                                     @RequestBody @GraphAuth JSONObject params) {
        //检查节点数量 + TODO:检查边配置
//        GraphDTO graphDTO = graphService.queryById(params.getLong("graphId"));
//        JSONObject graphData = JSONObject.parseObject(graphDTO.getDataJson());
//        List<CategoryVO> categories = graphData.getJSONArray("categories").toJavaList(CategoryVO.class);
//        Long NodeCnt = categories.stream().mapToLong(c-> Long.parseLong(c.getValue())).sum();
//        if (NodeCnt > 5000) {
//            return ApiResult.valueOf(ApiResultCode.GRAPH_NODE_LIMIT);
//        }

        TaskDTO taskDTO = graphService.syncGraphSchema(params.getLong("graphId"));
        List<Long> sessionIds = new ArrayList<>();
        //触发一次
        Long sessionId = dagScheduler.trigger(taskDTO.getPipelineId(), taskDTO.getId(), true);
        sessionIds.add(sessionId);
        return ApiResult.valueOf(sessionIds);
    }

    @PostMapping(value = "/addCategory")
    @ResponseBody
    @ApiOperation(value = "addCategory", notes = "addCategory")
    @Transactional
    public ApiResult<CategoryVO> addCategory(HttpServletRequest request,
                                                 @RequestBody
                                                 @GraphAuth
                                                 @CheckNull(field = "category")
                                                         JSONObject params) {
        Long gid = params.getLong("graphId");
        CategoryVO vo = GraphUtil.parseJSONObject2Obj(params, "category", CategoryVO.class);
        GraphVO context = new GraphVO();
        vo = graphService.addCategory(gid, vo, context);
        graphActionService.addActionForGraph(ActionEnum.ADD, context, null);
        return ApiResult.valueOf(vo);
    }

    @PostMapping(value = "/addEdge")
    @ResponseBody
    @ApiOperation(value = "addEdge", notes = "addEdge")
    @Transactional
    public ApiResult<EdgeVO> addEdge(HttpServletRequest request,
                                             @RequestBody
                                             @GraphAuth
                                             @CheckNull(field = "edge")
                                                     JSONObject params) {
        Long gid = params.getLong("graphId");
        EdgeVO vo = GraphUtil.parseJSONObject2Obj(params, "edge", EdgeVO.class);
        GraphVO context = new GraphVO();
        vo = graphService.addEdge(gid, vo, context);
        if (vo == null) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_EDGE_DUP);
        }
        graphActionService.addActionForGraph(ActionEnum.ADD, context, null);
        return ApiResult.valueOf(vo);
    }

    @PostMapping(value = "/deleteCategory")
    @ResponseBody
    @ApiOperation(value = "deleteCategory", notes = "deleteCategory")
//    @Transactional
    @Deprecated
    public ApiResult<Void> deleteCategory(HttpServletRequest request,
                                             @RequestBody JSONObject params) {
        if (params == null || !params.containsKey("graphId") || !params.containsKey("id")) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        Long gid = params.getLong("graphId");
        String cid = params.getString("id");
        graphService.deleteCategory(gid, cid);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/deleteEdge")
    @ResponseBody
    @ApiOperation(value = "deleteEdge", notes = "deleteEdge")
//    @Transactional
    @Deprecated
    public ApiResult<Void> deleteEdge(HttpServletRequest request,
                                          @RequestBody JSONObject params) {
        if (params == null || !params.containsKey("graphId") || !params.containsKey("id")) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        Long gid = params.getLong("graphId");
        String eid = params.getString("id");
        graphService.deleteEdge(gid, eid);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/deleteNode")
    @ResponseBody
    @ApiOperation(value = "deleteNode", notes = "deleteNode")
//    @Transactional
    @Deprecated
    public ApiResult<Void> deleteNode(HttpServletRequest request,
                                      @RequestBody JSONObject params) {
        if (params == null || !params.containsKey("graphId") || !params.containsKey("id")) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        Long gid = params.getLong("graphId");
        String nid = params.getString("id");
        graphService.deleteNode(gid, nid);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/deleteLink")
    @ResponseBody
    @ApiOperation(value = "deleteLink", notes = "deleteLink")
//    @Transactional
    @Deprecated
    public ApiResult<Void> deleteLink(HttpServletRequest request,
                                      @RequestBody JSONObject params) {
        if (params == null || !params.containsKey("graphId") || !params.containsKey("id")) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        Long gid = params.getLong("graphId");
        String lid = params.getString("id");
        graphService.deleteLink(gid, lid);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/batchDeleteCategoriesAndEdges")
    @ResponseBody
    @ApiOperation(value = "batchDeleteCategoriesAndEdges", notes = "batchDeleteCategoriesAndEdges")
    @Transactional
    public ApiResult<Void> batchDeleteCategoriesAndEdges(HttpServletRequest request,
                                                     @RequestBody @GraphAuth JSONObject params) {
        Long gid = params.getLong("graphId");
        List<String> cids = new ArrayList<>();
        List<String> eids = new ArrayList<>();
        if (params.containsKey("categoryIds")) {
            cids = GraphUtil.parseJSONArray2List(params, "categoryIds", String.class);
        }
        if (params.containsKey("edgeIds")) {
            eids = GraphUtil.parseJSONArray2List(params, "edgeIds", String.class);
        }
        GraphVO ctx1 = new GraphVO();
        JSONObject context = new JSONObject();
        graphService.batchDeleteCategoriesAndEdges(gid, cids, eids, ctx1, context);
        graphActionService.addActionForGraph(ActionEnum.DELETE, ctx1, null, null, context);

        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/batchDeleteNodesAndLinks")
    @ResponseBody
    @ApiOperation(value = "batchDeleteNodesAndLinks", notes = "batchDeleteNodesAndLinks")
    @Transactional
    public ApiResult<Void> batchDeleteNodesAndLinks(HttpServletRequest request,
                                                         @RequestBody @GraphAuth JSONObject params) {
        Long gid = params.getLong("graphId");
        List<String> nids = new ArrayList<>();
        List<String> lids = new ArrayList<>();
        if (params.containsKey("nodeIds")) {
            nids = GraphUtil.parseJSONArray2List(params, "nodeIds", String.class);
        }
        if (params.containsKey("linkIds")) {
            lids = GraphUtil.parseJSONArray2List(params, "linkIds", String.class);
        }
        graphService.batchDeleteNodesAndLinks(gid, nids, lids);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/addCategoryAttr")
    @ResponseBody
    @ApiOperation(value = "addCategoryAttr", notes = "addCategoryAttr")
    @Transactional
    public ApiResult<Void> addCategoryAttr(HttpServletRequest request,
                                                @RequestBody
                                                @GraphAuth
                                                @CheckNull(field = "categoryId")
                                                @CheckNull(field = "attr")
                                                        JSONObject params) {
        Long gid = params.getLong("graphId");
        String cid = params.getString("categoryId");
        CategoryAttrVO attr = GraphUtil.parseJSONObject2Obj(params, "attr", CategoryAttrVO.class);
        GraphVO ctx1 = new GraphVO();
        GraphVO ctx2 = new GraphVO();
        graphService.addCategoryAttr(gid, cid, attr, ctx1, ctx2);
        graphActionService.addActionForGraph(ActionEnum.UPDATE, ctx1, ctx2);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/removeCategoryAttr")
    @ResponseBody
    @ApiOperation(value = "removeCategoryAttr", notes = "removeCategoryAttr")
    @Transactional
    public ApiResult<Void> removeCategoryAttr(HttpServletRequest request,
                                          @RequestBody
                                          @GraphAuth
                                          @CheckNull(field = "categoryId")
                                          @CheckNull(field = "attrId")
                                                  JSONObject params) {
        Long gid = params.getLong("graphId");
        String cid = params.getString("categoryId");
        String attrId = params.getString("attrId");
        GraphVO ctx1 = new GraphVO();
        GraphVO ctx2 = new GraphVO();
        graphService.removeCategoryAttr(gid, cid, attrId, ctx1, ctx2);
        graphActionService.addActionForGraph(ActionEnum.UPDATE, ctx1, ctx2);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/updateCategory")
    @ResponseBody
    @ApiOperation(value = "updateCategory", notes = "updateCategory")
    @Transactional
    public ApiResult<Void> updateCategory(HttpServletRequest request,
                                                 @RequestBody
                                                 @GraphAuth
                                                 @CheckNull(field = "category")
                                                         JSONObject params) {
        Long gid = params.getLong("graphId");
        CategoryVO vo = GraphUtil.parseJSONObject2Obj(params, "category",CategoryVO.class);
        if (vo.getId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        GraphVO ctx1 = new GraphVO();
        GraphVO ctx2 = new GraphVO();
        graphService.updateCategory(gid, vo, ctx1, ctx2);
        graphActionService.addActionForGraph(ActionEnum.UPDATE, ctx1, ctx2);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/updateEdge")
    @ResponseBody
    @ApiOperation(value = "updateEdge", notes = "updateEdge")
    @Transactional
    public ApiResult<Void> updateEdge(HttpServletRequest request,
                                           @RequestBody
                                           @GraphAuth
                                           @CheckNull(field = "edge")
                                                   JSONObject params) {
        Long gid = params.getLong("graphId");
        EdgeVO vo = GraphUtil.parseJSONObject2Obj(params, "edge",EdgeVO.class);
        if (vo.getId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        GraphVO ctx1 = new GraphVO();
        GraphVO ctx2 = new GraphVO();
        graphService.updateEdge(gid, vo, ctx1, ctx2);
        graphActionService.addActionForGraph(ActionEnum.UPDATE, ctx1, ctx2);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/updateNode")
    @ResponseBody
    @ApiOperation(value = "updateNode", notes = "updateNode")
    @Transactional
    public ApiResult<Void> updateNode(HttpServletRequest request,
                                          @RequestBody
                                          @GraphAuth
                                          @CheckNull(field = "node")
                                                  JSONObject params) {
        Long gid = params.getLong("graphId");
        NodeVO vo = GraphUtil.parseJSONObject2Obj(params, "node",NodeVO.class);
        if (vo.getId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        graphService.updateNode(gid, vo);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/updateLink")
    @ResponseBody
    @ApiOperation(value = "updateLink", notes = "updateLink")
    @Transactional
    public ApiResult<Void> updateLink(HttpServletRequest request,
                                      @RequestBody
                                      @GraphAuth
                                      @CheckNull(field = "link")
                                              JSONObject params) {
        Long gid = params.getLong("graphId");
        LinkVO vo = GraphUtil.parseJSONObject2Obj(params, "link", LinkVO.class);
        if (vo.getId() == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        graphService.updateLink(gid, vo);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/batchUpdate")
    @ResponseBody
    @ApiOperation(value = "batchUpdate", notes = "batchUpdate")
    @Transactional
    public ApiResult<Void> batchUpdate(HttpServletRequest request,
                                      @RequestBody @GraphAuth JSONObject params) {
        Long gid = params.getLong("graphId");
        List<Float> size = GraphUtil.parseJSONArray2List(params, "size", Float.class);
        List<NodeVO> nodes = GraphUtil.parseJSONArray2List(params, "nodes", NodeVO.class);
        List<LinkVO> links = GraphUtil.parseJSONArray2List(params, "links", LinkVO.class);

        graphService.batchUpdate(gid, nodes, links, size);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/queryElementById")
    @ResponseBody
    @ApiOperation(value = "queryElementById", notes = "queryElementById")
    @Transactional
    @Deprecated
    public ApiResult<JSONObject> queryElementById(HttpServletRequest request,
                                      @RequestBody JSONObject params) {
        if (params == null || !params.containsKey("graphId") || !params.containsKey("id")) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        Long gid = params.getLong("graphId");
        String status = graphInstanceService.queryLatestStatus(gid);
        if (!status.equals("SUCCESS")) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_DATA_NOT_DONE);
        }
        String elementId = params.getString("id");
        JSONObject response = graphService.queryElementById(gid, elementId);
        return ApiResult.valueOf(response);
    }

    @PostMapping(value = "/queryPath")
    @ResponseBody
    @ApiOperation(value = "queryPath", notes = "queryPath")
    @Transactional
    public ApiResult<List<List<String>>> queryPath(HttpServletRequest request,
                                                  @RequestBody
                                                  @GraphAuth
                                                  @CheckNull(field = "srcId")
                                                  @CheckNull(field = "tarId")
                                                  @CheckNull(field = "param")
                                                          JSONObject params) {
        Long gid = params.getLong("graphId");
        String srcId = params.getString("srcId");
        String tarId = params.getString("tarId");
        JSONObject param = params.getJSONObject("param");
        String status = graphInstanceService.queryLatestStatus(gid);
        if (!status.equals("SUCCESS")) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_DATA_NOT_DONE);
        }
        List<List<String>> results = graphService.queryPath(gid, srcId, tarId, param);
        graphService.closeTransactions();
        return ApiResult.valueOf(results);
    }

    @PostMapping(value = "/queryCluster")
    @ResponseBody
    @ApiOperation(value = "queryCluster", notes = "queryCluster")
    @Transactional
    public ApiResult<Map<String, List<String>>> queryCluster(HttpServletRequest request,
                                                           @RequestBody
                                                           @GraphAuth
                                                           @CheckNull(field = "nodeIds")
                                                           @CheckNull(field = "param")
                                                                   JSONObject params) {
        Long gid = params.getLong("graphId");
        String status = graphInstanceService.queryLatestStatus(gid);
        if (!status.equals("SUCCESS")) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_DATA_NOT_DONE);
        }
        List<String> refIdList = GraphUtil.parseJSONArray2List(params, "nodeIds", String.class);
        JSONObject param = params.getJSONObject("param");
        Map<String, List<String>> result = graphService.queryCluster(gid, refIdList, param);
        graphService.closeTransactions();
        return ApiResult.valueOf(result);
    }

    @PostMapping(value = "/saveWidget")
    @ResponseBody
    @ApiOperation(value = "saveWidget", notes = "saveWidget")
    @Transactional
    public ApiResult<Long> saveWidget(HttpServletRequest request,
                                                             @RequestBody @GraphAuth JSONObject params) {
        Long gid = params.getLong("graphId");
        String graphName = params.getString("graphName");
        if (graphName == null) {
            graphName = "图构建";
        }
        Long WidgetId = graphService.saveWidget(gid, "task", graphName);
        return ApiResult.valueOf(WidgetId);
    }

    @PostMapping(value = "/search")
    @ResponseBody
    @ApiOperation(value = "search", notes = "search")
    @Transactional
    public ApiResult<JSONObject> search(HttpServletRequest request,
                                      @RequestBody
                                      @GraphAuth
                                      @CheckNull(field = "categoryIds")
                                      @CheckNull(field = "predicate")
                                      @CheckNull(field = "mode")
                                              JSONObject params) {
        Long gid = params.getLong("graphId");
        List<String> categoryIds = GraphUtil.parseJSONArray2List(params, "categoryIds", String.class);
        String predicate = params.getString("predicate");
        Integer mode;
        try {
            mode = params.getInteger("mode");
        } catch (Exception e) {
            mode = 2;
        }
        if (mode == null || (mode != 1 && mode != 2)) {
            mode = 2;
        }
        String status = graphInstanceService.queryLatestStatus(gid);
        if (!status.equals("SUCCESS")) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_DATA_NOT_DONE);
        }
        JSONObject results = graphAnalysisService.search(gid, categoryIds, mode, predicate);
        graphService.closeTransactions();
        if (results == null) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        return ApiResult.valueOf(results);
    }

    @PostMapping(value = "/queryEdgeConfigure")
    @ResponseBody
    @ApiOperation(value = "queryEdgeConfigure", notes = "queryEdgeConfigure")
    @Transactional
    public ApiResult<JSONObject> queryEdgeConfigure(HttpServletRequest request,
                                        @RequestBody
                                        @GraphAuth
                                        @CheckNull(field = "edgeId")
                                                JSONObject params) {
        Long gid = params.getLong("graphId");
        String eid = params.getString("edgeId");
        JSONObject result = graphService.queryEdgeConfigure(gid, eid);
        return ApiResult.valueOf(result);
    }

    @PostMapping(value = "/saveEdgeConfigure")
    @ResponseBody
    @ApiOperation(value = "saveEdgeConfigure", notes = "saveEdgeConfigure")
    @Transactional
    public ApiResult<Void> saveEdgeConfigure(HttpServletRequest request,
                                               @RequestBody
                                               @GraphAuth
                                               @CheckNull(field = "edgeId")
                                               @CheckNull(field = "leftHeaderName")
                                               @CheckNull(field = "rightHeaderName")
                                                       JSONObject params) {
        Long gid = params.getLong("graphId");
        String eid = params.getString("edgeId");
        String leftHeaderName = params.getString("leftHeaderName");
        String rightHeaderName = params.getString("rightHeaderName");
        GraphVO ctx1 = new GraphVO();
        GraphVO ctx2 = new GraphVO();
        graphService.saveEdgeConfigure(gid, eid, leftHeaderName, rightHeaderName, ctx1, ctx2);
        graphActionService.addActionForGraph(ActionEnum.EDGE_CONF, ctx1, ctx2);
        return ApiResult.valueOf(ApiResultCode.SUCCESS);
    }

    @PostMapping(value = "/addAction")
    @ResponseBody
    @ApiOperation(value = "addAction", notes = "addAction")
    @Transactional
    public ApiResult<CategoryCleanAction> addAction(HttpServletRequest request,
                                             @RequestBody
                                             @GraphAuth
                                             @CheckNull(field = "categoryId")
                                             @CheckNull(field = "data")
                                                     JSONObject params) {
        Long gid = params.getLong("graphId");
        String cid = params.getString("categoryId");
        JSONObject data = params.getJSONObject("data");
        List<JSONObject> ctx1 = new ArrayList<>();
        CategoryCleanAction action = graphService.addAction(gid, cid, data, ctx1);
        if (action == null) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_CATEGORY_CLEAN_ACTION_ID_NOT_FOUND);
        }
        graphActionService.addCleanAction(ActionEnum.CLEAN_ADD, ctx1, null, gid);
        return ApiResult.valueOf(action);
    }

    @PostMapping(value = "/queryAction")
    @ResponseBody
    @ApiOperation(value = "queryAction", notes = "queryAction")
    public ApiResult<List<CategoryCleanAction>> queryAction(HttpServletRequest request,
                                                            @RequestBody
                                                            @GraphAuth
                                                            @CheckNull(field = "categoryId")
                                                                    JSONObject params) {
        Long gid = params.getLong("graphId");
        String cid = params.getString("categoryId");
        //check category id if exist
        graphService.getCategoryByCId(gid, cid);
        List<CategoryCleanAction> actions = graphService.queryAction(cid);
        return ApiResult.valueOf(actions);
    }

    @PostMapping(value = "/deleteAction")
    @ResponseBody
    @ApiOperation(value = "deleteAction", notes = "deleteAction")
    public ApiResult<CategoryCleanAction> deleteAction(HttpServletRequest request,
                                                       @RequestBody
                                                       @GraphAuth
                                                       @CheckNull(field = "categoryId")
                                                       @CheckNull(field = "id")
                                                               JSONObject params) {
        Long gid = params.getLong("graphId");
        String cid = params.getString("categoryId");
        Long actionId;
        try {
            actionId = params.getLong("id");
        } catch (Exception e) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        List<JSONObject> ctx1 = new ArrayList<>();
        CategoryCleanAction action = graphService.deleteActions(gid, cid, actionId, ctx1);
        if (action == null) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_CATEGORY_CLEAN_ACTION_ID_NOT_FOUND);
        }
        graphActionService.addCleanAction(ActionEnum.CLEAN_DELETE, ctx1, null, gid);
        return ApiResult.valueOf(action);
    }

    @PostMapping(value = "/updateAction")
    @ResponseBody
    @ApiOperation(value = "updateAction", notes = "updateAction")
    @Transactional
    public ApiResult<CategoryCleanAction> updateAction(HttpServletRequest request,
                                             @RequestBody
                                             @GraphAuth
                                             @CheckNull(field = "categoryId")
                                             @CheckNull(field = "data")
                                                     JSONObject params) {
        Long gid = params.getLong("graphId");
        String cid = params.getString("categoryId");
        JSONObject data = params.getJSONObject("data");
        if (!data.containsKey("id")) {
            return ApiResult.valueOf(ApiResultCode.PARAM_ERROR);
        }
        List<JSONObject> ctx1 = new ArrayList<>();
        List<JSONObject> ctx2 = new ArrayList<>();
        CategoryCleanAction action = graphService.updateAction(gid, cid, data, ctx1, ctx2);
        if (action == null) {
            return ApiResult.valueOf(ApiResultCode.GRAPH_CATEGORY_CLEAN_ACTION_ID_NOT_FOUND);
        }
        graphActionService.addCleanAction(ActionEnum.CLEAN_UPDATE, ctx1, ctx2, gid);
        return ApiResult.valueOf(action);
    }

    @PostMapping(value = "/updateSemantic")
    @ResponseBody
    @ApiOperation(value = "updateSemantic", notes = "updateSemantic")
    @Transactional
    public ApiResult<CategoryVO> updateSemantic(HttpServletRequest request,
                                                       @RequestBody
                                                       @GraphAuth
                                                       @CheckNull(field = "categoryId")
                                                       @CheckNull(field = "data")
                                                               JSONObject params) {
        Long gid = params.getLong("graphId");
        String cid = params.getString("categoryId");
        JSONObject data = params.getJSONObject("data");
        CategoryVO category = graphService.updateSemantic(gid, cid, data);
        return ApiResult.valueOf(category);
    }

    @PostMapping(value = "/undo")
    @ResponseBody
    @ApiOperation(value = "undo", notes = "undo")
    @Transactional
    public ApiResult<JSONObject> undo(HttpServletRequest request,
                                      @RequestBody @GraphAuth JSONObject params) {
        Long gid = params.getLong("graphId");
        GraphActionDTO graphActionDTO = graphActionService.undo(gid);
        if (graphActionDTO == null) {
            return ApiResult.valueOf(ApiResultCode.UNDO_FAILED, null, "撤销失败， 撤销栈空");
        } else {
            return ApiResult.valueOf(graphActionService.actionElement(graphActionDTO));
        }
    }

    @PostMapping(value = "/redo")
    @ResponseBody
    @ApiOperation(value = "redo", notes = "redo")
    @Transactional
    public ApiResult<JSONObject> redo(HttpServletRequest request,
                                      @RequestBody @GraphAuth JSONObject params) {
        Long gid = params.getLong("graphId");
        GraphActionDTO graphActionDTO = graphActionService.redo(gid);
        if (graphActionDTO == null) {
            return ApiResult.valueOf(ApiResultCode.REDO_FAILED, null, "重做失败, 重做栈空");
        } else {
            return ApiResult.valueOf(graphActionService.actionElement(graphActionDTO));
        }
    }


    @RequestMapping(value = "/download")
    @ApiOperation(value = "download", notes = "下载数据")
    public void download(HttpServletRequest request, HttpServletResponse response,
                         @RequestParam("graphId") @GraphAuth(field =  StringUtils.EMPTY) String graphId,
                         @RequestParam(value = "format", required = false) String format) {
        if (format == null) {
            format = GraphFileFormatEnum.JSON.getDesc();
        }
        GraphDTO graph = graphService.queryById(Long.parseLong(graphId));
        graphService.downloadData(response, graph, format, true);
    }

    @PostMapping(value = "/loadToAnalysis")
    @ResponseBody
    @ApiOperation(value = "loadToAnalysis", notes = "导入图分析")
    @Transactional
    public ApiResult<JSONObject> loadToAnalysis(HttpServletRequest request,
                                                @RequestBody @ProjectRoleAuth @GraphAuth JSONObject params) {
        Long gid = params.getLong("graphId");
        Long projectId = params.getLong("projectId");
        String name = params.getString("name");
        GraphDTO newGraph = graphAnalysisService.addGraphByProject(projectId, name);
        Long newGid = newGraph.getId();
        Long graphInstanceId = graphAnalysisService.loadData(newGid, gid, GraphFileFormatEnum.GRAPH_BUILD);
        JSONObject ret = new JSONObject();
        ret.put("graphId", newGid);
        ret.put("loadId", graphInstanceId);
        return ApiResult.valueOf(ret);
    }
}
